﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace Erebos.GameScreenFiles
{
    public class Camera
    {
        public static Matrix ViewMatrix;
        public static Matrix ProjectionMatrix;
        public static Vector3 CameraPosition;
        public static float LeftRightRot = -3.0f;
        public static float UpDownRot = -MathHelper.Pi / 10.0f;
        public static GraphicsDevice Device;
        public static MouseState originalMouseState;

        public const float RotationSpeed = 0.3f;
        public const float MoveSpeed = 50.0f;

        private static KeyboardState _oldState = Keyboard.GetState();
        private static bool _oldActive = true;

        public static World World;

        private static bool _isJump;
        private static bool _down = false;
        private static Vector3 _startJump;

        public static FillMode FillMode = FillMode.Solid;

        public static void SetUpCamera(GraphicsDevice device, World world)
        {
            CameraPosition = new Vector3(0, 0, 0);
            World = world;
            Device = device;
            Refresh();
            ProjectionMatrix = Matrix.CreatePerspectiveFieldOfView(1, device.Viewport.AspectRatio, 1.0f, 2000.0f);
            Mouse.SetPosition(device.Viewport.Width / 2, device.Viewport.Height / 2);
            originalMouseState = Mouse.GetState();
        }

        public static void Update(float amount)
        {
            if (MainGame.IsActive && _oldActive == true)
            {
                MouseState currentMouseState = Mouse.GetState();
                if (currentMouseState != originalMouseState && currentMouseState.RightButton == ButtonState.Pressed)
                {
                    float xDifference = currentMouseState.X - originalMouseState.X;
                    float yDifference = currentMouseState.Y - originalMouseState.Y;
                    LeftRightRot -= RotationSpeed * xDifference * amount;
                    UpDownRot -= RotationSpeed * yDifference * amount;
                    if (currentMouseState.X < 0)
                        Mouse.SetPosition(ScreenSizeHelper.SizeWidth, currentMouseState.Y);
                    if (currentMouseState.X > ScreenSizeHelper.SizeWidth)
                        Mouse.SetPosition(0, currentMouseState.Y);
                    if (currentMouseState.Y < 0)
                        Mouse.SetPosition(0, ScreenSizeHelper.SizeHeight);
                    if (currentMouseState.Y > ScreenSizeHelper.SizeHeight)
                        Mouse.SetPosition(currentMouseState.X, 0);

                    currentMouseState = Mouse.GetState();
                    Refresh();
                }

                originalMouseState = currentMouseState;

                Vector3 moveVector = new Vector3(0, 0, 0);
                KeyboardState keyState = Keyboard.GetState();
                if (keyState.IsKeyDown(Keys.Up) || keyState.IsKeyDown(Keys.W))
                    moveVector += new Vector3(0, 0, -1);
                if (keyState.IsKeyDown(Keys.Down) || keyState.IsKeyDown(Keys.S))
                    moveVector += new Vector3(0, 0, 1);
                if (keyState.IsKeyDown(Keys.Right) || keyState.IsKeyDown(Keys.D))
                    moveVector += new Vector3(1, 0, 0);
                if (keyState.IsKeyDown(Keys.Left) || keyState.IsKeyDown(Keys.A))
                    moveVector += new Vector3(-1, 0, 0);
                if (keyState.IsKeyDown(Keys.Q))
                    moveVector += new Vector3(0, 1, 0);
                if (keyState.IsKeyDown(Keys.Z))
                    moveVector += new Vector3(0, -1, 0);
                if (keyState.IsKeyDown(Keys.Space) && _oldState.IsKeyUp(Keys.Space) && !_isJump)
                {
                    _isJump = true;
                    _startJump = CameraPosition;
                }
                if (keyState.IsKeyDown(Keys.F1) && _oldState.IsKeyUp(Keys.F1))
                {
                    if (FillMode == FillMode.Solid)
                        FillMode = FillMode.WireFrame;
                    else
                        FillMode = FillMode.Solid;
                }
                if (keyState.IsKeyDown(Keys.F2) && _oldState.IsKeyUp(Keys.F2))
                {
                    World.CreateExplosion(new Vector3(CameraPosition.X +  80, CameraPosition.Y - 10, -CameraPosition.Z + 80));
                }

                if (_isJump)
                {
                    if (!_down)
                    {
                        CameraPosition.Y += MoveSpeed * 1.5f * amount;
                        Refresh();
                        if (CameraPosition.Y >= _startJump.Y + 30f)
                            _down = true;
                    }
                    else
                    {
                        CameraPosition.Y -= MoveSpeed * 1.5f * amount;
                        Refresh();
                        if (CameraPosition.Y <= World.GetHeightData(new Vector3(CameraPosition.X, CameraPosition.Y, -CameraPosition.Z)) + 10)
                        {
                            _isJump = false;
                            _down = false;
                        }
                    }

                    Vector3 tmpCam = CameraPosition + MoveSpeed * Vector3.Transform(moveVector * amount, Matrix.CreateRotationY(LeftRightRot));
                    if(World.GetHeightData(new Vector3(tmpCam.X, tmpCam.Y, -tmpCam.Z)) + 10 < CameraPosition.Y)
                        AddToCameraPosition(moveVector * amount);
                }
                else
                {
                    Vector3 tmpCam = CameraPosition + MoveSpeed * Vector3.Transform(moveVector * amount, Matrix.CreateRotationY(LeftRightRot));
                    if ((World.GetHeightData(new Vector3(tmpCam.X, tmpCam.Y, -tmpCam.Z)) + 10) - CameraPosition.Y < 2.5f && !_isJump)
                    {
                        AddToCameraPosition(moveVector * amount);
                        CameraPosition.Y = World.GetHeightData(new Vector3(CameraPosition.X, CameraPosition.Y, -CameraPosition.Z)) + 10;
                    } 
                    else if (CameraPosition.Y - 10 <= 0) //todo: Change this to !checkIsInWorld
                    {
                        AddToCameraPosition(moveVector * amount);
                        CameraPosition.Y = World.GetHeightData(new Vector3(CameraPosition.X, CameraPosition.Y, -CameraPosition.Z)) + 10;
                    }
                }
            }
            if (MainGame.IsActive && _oldActive == false)
            {
                Mouse.SetPosition(Device.Viewport.Width / 2, Device.Viewport.Height / 2);
                originalMouseState = Mouse.GetState();
            }
            _oldActive = MainGame.IsActive;
            _oldState = Keyboard.GetState();
        }

        private static void AddToCameraPosition(Vector3 vectorToAdd)
        {
            Matrix cameraRotation = Matrix.CreateRotationY(LeftRightRot);
            Vector3 rotatedVector = Vector3.Transform(vectorToAdd, cameraRotation);
            CameraPosition += MoveSpeed * rotatedVector;
            Refresh();
        }

        public static void ChangeScreenSize()
        {
            Mouse.SetPosition(Device.Viewport.Width / 2, Device.Viewport.Height / 2);
            originalMouseState = Mouse.GetState();
        }

        public static void Refresh()
        {
            Matrix cameraRotation = Matrix.CreateRotationX(UpDownRot) * Matrix.CreateRotationY(LeftRightRot);

            Vector3 cameraOriginalTarget = new Vector3(0, 0, -1);
            Vector3 cameraRotatedTarget = Vector3.Transform(cameraOriginalTarget, cameraRotation);
            Vector3 cameraFinalTarget = CameraPosition + cameraRotatedTarget;

            Vector3 cameraOriginalUpVector = new Vector3(0, 1, 0);
            Vector3 cameraRotatedUpVector = Vector3.Transform(cameraOriginalUpVector, cameraRotation);

            /*Vector3 v = Vector3.Forward * 1.5f;
            Matrix forwardMovement = Matrix.CreateRotationY(LeftRightRot);
            v = Vector3.Transform(v, forwardMovement);
            Vector3 campos = CameraPosition; campos.X += v.X; campos.Z += v.Z;*/
            ViewMatrix = Matrix.CreateLookAt(CameraPosition, cameraFinalTarget, cameraRotatedUpVector);

        }
    }
}
